﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;


namespace Pacman
{
    class MouvementFuite : Mouvement
    {
        private bool isBlue = true;
        private Random nbRand;

        public MouvementFuite(byte[,] map) : base(map)
        {
            nbRand = new Random();
        }

        public MouvementFuite(Fantome _fantome, byte[,] map)
            : base(_fantome,map)
        {
            nbRand = new Random();
        }

        public MouvementFuite(Fantome _fantome, byte[,] map, int _indDividVitesse)
            : base(_fantome, map)
        {
            nbRand = new Random();
            indDividVitesse = _indDividVitesse;
        }

        //Le mouvement de fuite est un Dijkstra inversé : on cherche le chemin le plus court et on essaye de prendre la direction opposée. Sauve qui peut !
        public override void Move(Jeu jeu, Sommet[,] mesSommets, Vector2 Destination, Fantome fantome)
        {

            //On transforme nos objets en sommets pour travailler avec Dijkstra
            Sommet _courant = mesSommets[(int)(getCase(fantome.Position).Y), (int)(getCase(fantome.Position).X)];
            Sommet _pacman = mesSommets[(int)getCase(Destination).Y, (int)getCase(Destination).X];

            //Initilialisation pour l'algorythme 
            _courant.Potentiel = 0;
            _courant.Marque = true;

            Sommet _suivant = _courant; //_suivant est la case testée par l'algorythme. La première case testée doit être la case du fantome
            Sommet caseInterdite = null; //La case d'où le fantome vient (elle sert à ne pas faire demi-tour)
            int nbPossibilites = 0; //Le nombre de choix de destination du fantome

            bool isBreak = false; //Petit bool qui nous sert à savoir si l'on a quitté la boucle (sert pour ne pas faire demi-tour)
            bool premiereBoucle = true;//Petit bool qui indique si l'on fait la première boucle de l'algo Dijkstra ou non

            

            //Initialisation de la case interdite : la case d'où vient le fantome donc la case actuelle moins la vitesse actuelle (si ce n'est pas le pacman)
            if (mesSommets[(int)_courant.Coordonnees.X - ((int)fantome.Vitesse.Y)/20, (int)_courant.Coordonnees.Y - ((int)fantome.Vitesse.X)/20] != null)
                if (mesSommets[(int)_courant.Coordonnees.X - ((int)fantome.Vitesse.Y)/20, (int)_courant.Coordonnees.Y - ((int)fantome.Vitesse.X)/20].Coordonnees != _pacman.Coordonnees)
                    caseInterdite = mesSommets[(int)_courant.Coordonnees.X - ((int)fantome.Vitesse.Y)/20, (int)_courant.Coordonnees.Y - ((int)fantome.Vitesse.X)/20];
                


            //On vérifie si le fantome est en phase de clignotement
            if (jeu.IsClignotement)
            {
                fantome.Texture = jeu.getTexture2D("images/FantomePeur" + (isBlue ? 0 : 1));
                isBlue = !isBlue;
            }


            //On aplique Dijkstra tant qu'on a pas trouvé le chemin le plus court vers le pacman
            while (_suivant.Coordonnees != _pacman.Coordonnees)
            {
                //Marquer le sommet testé
                _suivant.Marque = true;


                //On va tester les 4 directions selon le même schéma : 

                //On vérifie quelles directions peut prendre le fantome : si la direction est possible (pas de mur) et si le sommet n'est pas la case Interdite
                if (HautPossible(MapToPix(_suivant.getVector())) && (mesSommets[(int)_suivant.Coordonnees.X - 1, (int)_suivant.Coordonnees.Y] != caseInterdite))
                {
                        //On atteint le sommet qui correspond à la case (ici la case du haut)
                        Sommet s = mesSommets[(int)_suivant.Coordonnees.X - 1, (int)_suivant.Coordonnees.Y];
                        if (s.Potentiel > _suivant.Potentiel + 1) //Si on l'a atteint par un chemin plus court que celui qu'on conaissait
                        {
                            mesSommets[(int)_suivant.Coordonnees.X - 1, (int)_suivant.Coordonnees.Y].pred = _suivant; //Alors on enregistre le nouveau chemin : le sommet "précédent" de ce sommet devient le sommet qui est actuellement testé, donc _suivant
                            mesSommets[(int)_suivant.Coordonnees.X - 1, (int)_suivant.Coordonnees.Y].Potentiel = _suivant.Potentiel + 1;//On enregistre son nouveau potentiel (la taille du nouveau chemin qu'on a trouvé pour y aller)
                        }
                    if (premiereBoucle)
                        nbPossibilites++; //On enregistre le nombre de possibilités qu'a le fantome ici
                    
                }

                //On test en bas
                if (BasPossible(MapToPix(_suivant.getVector())) && (mesSommets[(int)_suivant.Coordonnees.X + 1, (int)_suivant.Coordonnees.Y] != caseInterdite))
                {
                   
                    
                        Sommet s = mesSommets[(int)_suivant.Coordonnees.X + 1, (int)_suivant.Coordonnees.Y];
                        if (s.Potentiel > _suivant.Potentiel + 1)
                        {
                            mesSommets[(int)_suivant.Coordonnees.X + 1, (int)_suivant.Coordonnees.Y].pred = _suivant;
                            mesSommets[(int)_suivant.Coordonnees.X + 1, (int)_suivant.Coordonnees.Y].Potentiel = _suivant.Potentiel + 1;
                        }
                    if (premiereBoucle)
                        nbPossibilites++;
                }

                //On test à gauche
                if (GauchePossible(MapToPix(_suivant.getVector())) && (mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y - 1] != caseInterdite))
                {
                   
                        Sommet s = mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y - 1];
                        if (s.Potentiel > _suivant.Potentiel + 1)
                        {
                            mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y - 1].pred = _suivant;
                            mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y - 1].Potentiel = _suivant.Potentiel + 1;
                        }
                    if (premiereBoucle)
                        nbPossibilites++;
                    
                }

                //On test à droite
                if (DroitePossible(MapToPix(_suivant.getVector())) && (mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y + 1] != caseInterdite))
                {
                    
                        Sommet s = mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y + 1];
                        if (s.Potentiel > _suivant.Potentiel + 1)
                        {
                            mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y + 1].pred = _suivant;
                            mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y + 1].Potentiel = _suivant.Potentiel + 1;
                        }
                    if (premiereBoucle)
                        nbPossibilites++;
                    
                }

                //On choisit maintenant le prochain sommet à tester (donc le prochain _suivant)
                if (nbPossibilites > 1 || !premiereBoucle)//Si jamais le fantome a plus d'une possibilité, ou alors pour toute autre boucle que la première
                {
                    int minimum = Sommet.INFINI;//On récupère la distance INFINI

                    //On parcourt tout notre tableau de Sommet
                    for (int i = 0; i < mesSommets.GetLength(0); i++)
                    {
                        for (int j = 0; j < mesSommets.GetLength(1); j++)
                        {
                            if (mesSommets[i, j] != null && !mesSommets[i, j].Marque && mesSommets[i, j].Potentiel < minimum)//Algo Dijkstra : le prochain sommet testé est le premier qu'on trouve avec un potentiel minimum, qui n'a pas déjà été visité
                            {
                                minimum = mesSommets[i, j].Potentiel; //Permet de trouver le potentiel minimum
                                _suivant = mesSommets[i, j];//Le sommet devient le prochain sommet testé
                            }
                        }
                    }
                }

                else //if (nbPossibilites > 1 || !premiereBoucle)  
                {
                    //Si le fantome n'a qu'une seule possibilité
                                
                                        //Si il peut continuer tout droit (il n'est pas au bout du couloir)
                                       if (mesSommets[(int)_courant.Coordonnees.X + ((int)fantome.Vitesse.Y)/20, (int)_courant.Coordonnees.Y + ((int)fantome.Vitesse.X)/20] != null)
                                        {
                                            //On ne change pas de vitesse
                                        }
                                        else //Sinon (il arrive dans un angle par exemple)
                                        {
                                            if (fantome.Vitesse.Y != 0) //Si il est en train de se déplacer vers le haut ou le bas
                                            {
                                                if (DroitePossible(MapToPix(_courant.getVector()))) //Si son couloir tourne à droite
                                                {
                                                    fantome.Vitesse = vDroite; //On va à droite
                                                }
                                                else if (GauchePossible(MapToPix(_courant.getVector())))//Sinon si son couloir tourne à gauche
                                                {
                                                    fantome.Vitesse = vGauche;//On va à gauche
                                                }
                                            }
                                            else if (fantome.Vitesse.X != 0)//Si il est en train de se déplacer vers la gauche ou la droite
                                            {
                                                if (BasPossible(MapToPix(_courant.getVector())))//Si son couloir tourne en bas
                                                {
                                                    fantome.Vitesse = vBas;//On va en bas
                                                }
                                                else if (HautPossible(MapToPix(_courant.getVector())))//Si son couloir tourne en haut
                                                {
                                                    fantome.Vitesse = vHaut;//On va en haut
                                                }
                                            }
                                        }

                                        
                                        isBreak = true;//Indique que l'on est sorti de la boucle car on était dans un couloir

                                        //TRES IMPORTANT : si le fantome est dans un couloir, on applique pas Dijkstra, il poursuit dans son couloir sans se poser de questions
                                        break;

                                    }
                

               
                //nbPossibilites = 0; //Si jamais on n'était pas dans un couloir, on réinitialise le nombre de possibilités pour le calculer correctement à la prochaine boucle
                premiereBoucle = false;//La première boucle est forcément passéee à ce moment

            } //fin while (_suivant.Coordonnees != _pacman.Coordonnees)


            //On va passer au résultat de l'algorythme : Dijkstra a trouvé le chemin le plus court vers le pacman ou alors le fantome était dans un couloir

            //Si on n'était pas dans un couloir
            if (!isBreak)
            {
                //On crée un Sommet qui va nous permettre de remonter jusqu'au sommet le plus proche du fantome
                Sommet _precedent = mesSommets[(int)_suivant.Coordonnees.X, (int)_suivant.Coordonnees.Y];

                //On remonte le chemin le plus court jusqu'à arriver à la case qui nous intéresse : la suivante sur laquelle le fantome va devoir se déplacer
                while (_precedent.pred != null && _precedent.pred.Coordonnees != _courant.Coordonnees)
                {
                    _precedent = _precedent.pred;
                }

                //On set la vitesse du fantome
                fantome.Vitesse = new Vector2((_precedent.Coordonnees.Y - getCase(fantome.Position).X)*20, (_precedent.Coordonnees.X - getCase(fantome.Position).Y)*20);
                
                    //Et on le fait aller dans l'autre sens si possible !
                    if (fantome.Vitesse.Y > 0) //Si il doit descendre
                    {
                        //On le fait aller en haut si possible
                        if (HautPossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X - 1, (int)_courant.Coordonnees.Y] != caseInterdite))
                        {
                            fantome.Vitesse = vHaut;
                        }
                        else if (nbPossibilites == 2)
                        {
                            if (GauchePossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X, (int)_courant.Coordonnees.Y - 1] != caseInterdite))
                                fantome.Vitesse = vGauche;
                            else
                                fantome.Vitesse = vDroite;
                        }
                        else
                        {
                            if (nbRand.Next() % 2 > 0)
                            {
                                if (GauchePossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X, (int)_courant.Coordonnees.Y - 1] != caseInterdite))
                                    fantome.Vitesse = vGauche;
                                else
                                    fantome.Vitesse = vDroite;

                            }
                            else
                            {
                                if (DroitePossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X, (int)_courant.Coordonnees.Y + 1] != caseInterdite))
                                    fantome.Vitesse = vDroite;
                                else
                                    fantome.Vitesse = vGauche;
                            }

                        }
                    }
                    else if (fantome.Vitesse.Y < 0)
                    {

                        if (BasPossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X + 1, (int)_courant.Coordonnees.Y] != caseInterdite))
                        {
                            fantome.Vitesse = vBas;
                        }
                        else if (nbPossibilites == 2)
                        {
                            if (GauchePossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X, (int)_courant.Coordonnees.Y - 1] != caseInterdite))
                                fantome.Vitesse = vGauche;
                            else
                                fantome.Vitesse = vDroite;
                        }
                        else
                        {
                            if (nbRand.Next() % 2 > 0)
                            {
                                if (GauchePossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X, (int)_courant.Coordonnees.Y - 1] != caseInterdite))
                                    fantome.Vitesse = vGauche;
                                else
                                    fantome.Vitesse = vDroite;
                            }
                            else
                            {
                                if (DroitePossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X, (int)_courant.Coordonnees.Y + 1] != caseInterdite))
                                    fantome.Vitesse = vDroite;
                                else
                                    fantome.Vitesse = vGauche;
                            }

                        }
                    }
                    else if (fantome.Vitesse.X > 0)
                    {
                        if (GauchePossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X, (int)_courant.Coordonnees.Y - 1] != caseInterdite))
                        {
                            fantome.Vitesse = vGauche;
                        }
                        else if (nbPossibilites == 2)
                        {
                            if (HautPossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X - 1, (int)_courant.Coordonnees.Y] != caseInterdite))
                                fantome.Vitesse = vHaut;
                            else
                                fantome.Vitesse = vBas;
                        }
                        else
                        {
                            if (nbRand.Next() % 2 > 0)
                            {
                                if (HautPossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X - 1, (int)_courant.Coordonnees.Y] != caseInterdite))
                                    fantome.Vitesse = vHaut;
                                else
                                    fantome.Vitesse = vBas;
                            }
                            else
                            {
                                if (BasPossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X + 1, (int)_courant.Coordonnees.Y] != caseInterdite))
                                    fantome.Vitesse = vBas;
                                else
                                    fantome.Vitesse = vHaut;
                            }

                        }
                    }
                    else if (fantome.Vitesse.X < 0)
                    {
                        if (DroitePossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X, (int)_courant.Coordonnees.Y + 1] != caseInterdite))
                        {
                            fantome.Vitesse = vDroite;
                        }
                        else if (nbPossibilites == 2)
                        {
                            if (HautPossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X - 1, (int)_courant.Coordonnees.Y] != caseInterdite))
                                fantome.Vitesse = vHaut;
                            else
                                fantome.Vitesse = vBas;
                        }
                        else
                        {
                            if (nbRand.Next() % 2 > 0)
                            {
                                if (HautPossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X - 1, (int)_courant.Coordonnees.Y] != caseInterdite))
                                    fantome.Vitesse = vHaut;
                                else
                                    fantome.Vitesse = vBas;
                            }
                            else
                            {
                                if (BasPossible(MapToPix(_courant.getVector())) && (mesSommets[(int)_courant.Coordonnees.X + 1, (int)_courant.Coordonnees.Y] != caseInterdite))
                                    fantome.Vitesse = vBas;
                                else
                                    fantome.Vitesse = vHaut;
                            }

                        }
                    }
                
                

            }//fin  if (!isBreak)

            //On réinitialise correctement notre tableau de Sommet
                for (int i = 0; i < mesSommets.GetLength(0); i++)
                {
                    for (int j = 0; j < mesSommets.GetLength(1); j++)
                    {
                        if (mesSommets[i, j] != null)
                        {
                            mesSommets[i, j].Marque = false;
                            mesSommets[i, j].Potentiel = Sommet.INFINI;
                            mesSommets[i, j].pred = null;
                        }
                    }
                }

        }
        
    }
}
